/*
    FreeModbus 主机协议栈在 FreeRTOS 操作系统、STM32 硬件平台上的串口（RS485）适配实现，
    核心功能包括串口（RS485）初始化、收发使能控制、字节收发、中断处理等，是 Modbus 主机与物理总线（RS485）交互的底层硬件接口。
 */
#include "FreeRTOS.h"
#include "task.h"
#include "gd32f30x.h"
#include "port.h"

/* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h"
#include "mbport.h"
#include "mbframe.h"
#include "event_groups.h"

// 条件编译：仅当启用 Modbus 主机 RTU 或 ASCII 模式时，编译以下串口适配代码
#if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED > 0

// 硬件资源
/**
 * @brief UART及关联RS485硬件信息结构体
 *
 * 用于集中存储UART（通用异步收发传输器）的硬件配置参数，包括UART本身的引脚、时钟、中断信息，
 * 以及关联的RS485通信所需的控制引脚信息，便于统一管理和初始化UART硬件资源。
 */
typedef struct {
    uint32_t uartNo;                  // UART编号（如UART0、UART1等，用于区分不同的UART外设）
    rcu_periph_enum rcuUart;          // UART外设的时钟枚举（属于RCU复位时钟单元，用于使能UART时钟，如RCU_USART0）
    rcu_periph_enum rcuUartGpio;      // UART对应GPIO端口的时钟枚举（用于使能GPIO时钟，如RCU_GPIOA）
    uint32_t uartGpio;                // UART引脚所在的GPIO端口（如GPIOA、GPIOB等，指定具体的GPIO外设）
    uint32_t uartTxPin;               // UART发送引脚（如GPIO_PIN_9，对应具体的GPIO引脚编号）
    uint32_t uartRxPin;               // UART接收引脚（如GPIO_PIN_10，对应具体的GPIO引脚编号）
    uint8_t uartIrq;                  // UART中断号（用于注册UART中断服务函数，如USART0_IRQn）
    rcu_periph_enum rcuRs485Control;  // RS485控制引脚的时钟枚举（使能RS485方向控制引脚的GPIO时钟）
    uint32_t rs485ControlGpio;        // RS485控制引脚所在的GPIO端口（如GPIOC，用于连接RS485的DE/RE引脚）
    uint32_t rs485ControlPin;         // RS485控制引脚（如GPIO_PIN_0，用于控制RS485芯片的收发方向切换）
} UartRs485HwInfo_t;

static UartRs485HwInfo_t uartRsHwInfo = { .uartNo = USART1,
                                          .rcuUart = RCU_USART1,
                                          .rcuUartGpio = RCU_GPIOA,
                                          .uartGpio = GPIOA,
                                          .uartTxPin = GPIO_PIN_2,
                                          .uartRxPin = GPIO_PIN_3,
                                          .uartIrq = USART1_IRQn,
                                          .rcuRs485Control = RCU_GPIOC,
                                          .rs485ControlGpio = GPIOC,
                                          .rs485ControlPin = GPIO_PIN_5
                                        };
// 引脚初始化
static void GpioInit(void)
{
    rcu_periph_clock_enable(uartRsHwInfo.rcuUartGpio);
    gpio_init(uartRsHwInfo.uartGpio, GPIO_MODE_AF_PP, GPIO_OSPEED_10MHZ, uartRsHwInfo.uartTxPin);
    gpio_init(uartRsHwInfo.uartGpio, GPIO_MODE_IPU, GPIO_OSPEED_10MHZ, uartRsHwInfo.uartRxPin);
    rcu_periph_clock_enable(uartRsHwInfo.rcuRs485Control);                                 //使能GPIOC的时钟
    gpio_init(uartRsHwInfo.rs485ControlGpio, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, uartRsHwInfo.rs485ControlPin);  //推挽输出
}
// uart初始化
static void UartInit(uint32_t baudRate)
{
    /* 使能UART时钟；*/
    rcu_periph_clock_enable(uartRsHwInfo.rcuUart);
    /* 复位UART；*/
    usart_deinit(uartRsHwInfo.uartNo);
    /* 通过USART_CTL0寄存器的WL设置字长；*/
    usart_word_length_set(uartRsHwInfo.uartNo, USART_WL_8BIT);
    /* 无校验位；*/
    usart_parity_config(uartRsHwInfo.uartNo, USART_PM_NONE);
    /* 1位停止位；*/
    usart_stop_bit_set(uartRsHwInfo.uartNo, USART_STB_1BIT);
    /* 设置波特率；*/
    usart_baudrate_set(uartRsHwInfo.uartNo, baudRate);
    /* 使能发送功能；*/
    usart_transmit_config(uartRsHwInfo.uartNo, USART_TRANSMIT_ENABLE);
    /*使能接收功能；*/
    usart_receive_config(uartRsHwInfo.uartNo, USART_RECEIVE_ENABLE);
    /* 使能串口中断；*/
    nvic_irq_enable(uartRsHwInfo.uartIrq, 5, 0);
    /* 在USART_CTL0寄存器中置位UEN位，使能UART；*/
    usart_enable(uartRsHwInfo.uartNo);

}

#define TRANS_RS485_TX_MODE() 		gpio_bit_set(uartRsHwInfo.rs485ControlGpio, uartRsHwInfo.rs485ControlPin)
#define TRANS_RS485_RX_MODE() 		gpio_bit_reset(uartRsHwInfo.rs485ControlGpio, uartRsHwInfo.rs485ControlPin)

/* ----------------------- Start implementation -----------------------------*/
// 初始化串口以及控制 RS485引脚
// ulBaudRate - 波特率  ucDataBits - 数据位 eParity - 校验位
BOOL xMBMasterPortSerialInit(UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity)
{
    (void)ucPORT;
    (void)ucDataBits;
    (void)eParity;
    GpioInit();
    UartInit(ulBaudRate);
    return TRUE;
}

//Modbus 主机串口收发使能
void vMBMasterPortSerialEnable(BOOL xRxEnable, BOOL xTxEnable)
{
    // 进入临界区，确保操作原子性
    ENTER_CRITICAL_SECTION();
    if (TRUE == xRxEnable) {
        usart_interrupt_enable(uartRsHwInfo.uartNo, USART_INT_RBNE);//使能接收中断
        TRANS_RS485_RX_MODE();
    } else {
        usart_interrupt_disable(uartRsHwInfo.uartNo, USART_INT_RBNE);//失能接收中断
        TRANS_RS485_TX_MODE();
    }

    // 处理发送使能控制
    if (TRUE == xTxEnable) {
        // USART_INT_TBE  发送缓冲区为空 使能后 会立即触发   USART_INT_TC 移位寄存器发送完成的中断
        usart_interrupt_enable(uartRsHwInfo.uartNo, USART_INT_TC); //使能发送中断
    } else {
        usart_interrupt_disable(uartRsHwInfo.uartNo, USART_INT_TC);//失能发送中断
        TRANS_RS485_RX_MODE();
    }
    // 退出临界区，恢复中断和任务调度
    EXIT_CRITICAL_SECTION();
}

/**
 * @brief  Modbus 主机串口发送字节接口
 */
BOOL xMBMasterPortSerialPutByte(CHAR ucByte)
{
    //printf("%02X ", ucByte);
    usart_data_transmit(uartRsHwInfo.uartNo, ucByte);
    return TRUE;
}

/**
 * @brief  Modbus 主机串口接收字节接口
 */
BOOL xMBMasterPortSerialGetByte(CHAR* pucByte)
{
    *pucByte = usart_data_receive(uartRsHwInfo.uartNo);
    return TRUE;
}


#ifdef USE_MODBUS_MASTER
void USART1_IRQHandler(void)
{
    // 高优先级任务唤醒标志：默认未唤醒
    BOOL xHigherPriorityTaskWoken = FALSE;
    //接收中断
    if (RESET != usart_interrupt_flag_get(uartRsHwInfo.uartNo, USART_INT_FLAG_RBNE)) {
        // 通知收到 1 字节
        xHigherPriorityTaskWoken = pxMBMasterFrameCBByteReceived();
        usart_interrupt_flag_clear(uartRsHwInfo.uartNo, USART_INT_FLAG_RBNE_ORERR);
    }
    // 发送中断
    if (RESET != usart_interrupt_flag_get(uartRsHwInfo.uartNo, USART_INT_FLAG_TC)) {
        //通知可以可发送下一字节数据
        xHigherPriorityTaskWoken = pxMBMasterFrameCBTransmitterEmpty();
        usart_interrupt_flag_clear(uartRsHwInfo.uartNo, USART_INT_FLAG_TC);
    }
    // 触发 RTOS 上下文切换
    portEND_SWITCHING_ISR(xHigherPriorityTaskWoken ? pdTRUE : pdFALSE);
}
#endif






#endif
